
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Xml;
using System.Security.Cryptography;

using Swaf;
using Swaf.BizObj;
using Swaf.BizObj.basic;
using Swaf.Container;
using Swaf.Crypto;
using Swaf.Xml;

using Syrinx;

using Splicer.Renderer;
using Splicer.Timeline;

namespace MediaCache
{
	/// <summary>
	/// Manages the image store directly within the file system. 
	/// </summary>
	/// <remarks>This class uses two directories, one as the "origionals" base location
	/// and the other as the "cache" base location.</remarks>
	public class VideoImageCache : FileSysImageCache
	{        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="req"></param>
        /// <param name="catalogName"></param>
		public VideoImageCache(LineInfoXmlElement req, Swaf.Container.XmlCatalogContainerNode.NameInfo catalogName)
			:base(req, catalogName)
		{
		}

		protected override MediaStream retrieveImageStream(string name, IBizObj scaleOptions, IBizObj imgAdjInfo)
		{
			if (name == null || name == "") return null;

			string fileName = calcName(name, scaleOptions, imgAdjInfo);
			if (!File.Exists(fileName))
				return null;

			if (fileName.EndsWith(".wmv"))
			{
				FileInfo vid = new FileInfo(fileName);
				DirectoryInfo framesDir = new DirectoryInfo(Cmn.pathCombine(vid.DirectoryName, "frames"));
				Directory.CreateDirectory(framesDir.FullName);
				framesDir.Attributes = framesDir.Attributes | FileAttributes.Hidden;
				framesDir = new DirectoryInfo(Cmn.pathCombine(vid.DirectoryName, "frames", vid.Name + ".frames"));
				Directory.CreateDirectory(framesDir.FullName);
				framesDir.Attributes = framesDir.Attributes | FileAttributes.Hidden;
				string frameFileName = Cmn.pathCombine(framesDir.FullName, "frame0.jpg");
				if (!File.Exists(frameFileName) || (File.GetLastWriteTimeUtc(frameFileName) < File.GetLastWriteTimeUtc(fileName)))
				{
					try
					{
						using (var timeline = new DefaultTimeline())
						{
							timeline.AddVideoGroup(24, 640, 480).AddTrack(); // we want 320x240 sized images
							timeline.AddVideo(fileName, 0, 1, 2);

							ImagesToDiskParticipant participant = new ImagesToDiskParticipant(24, 640, 480, framesDir.FullName, 0);

							using (var render = new NullRenderer(timeline, null, new ICallbackParticipant[] { participant }))
							{
								render.Render();
							}
						}
					}
					catch (Exception e)
					{
						throw new MediaCacheException(string.Format("Unable to generate image from video frame on file: {0}", fileName), e);
					}
				}

				if (File.Exists(frameFileName))
				{
					Stream fs = new FileStream(frameFileName, FileMode.Open, FileAccess.Read);
					if (myCrypto != null)
						fs = myCrypto.createCryptoStream(fs);
					FileInfo frameFile = new FileInfo(frameFileName);
					string streamName = Cmn.pathCombine(frameFile.Directory.Name, frameFile.Name);
					return new MediaStream(Path.GetExtension(frameFileName), fs, streamName);
				}
			}
			else
				return base.retrieveImageStream(name, scaleOptions, imgAdjInfo);

			return null;
		}

		protected override string MediaBizObjType {get{return "VideoMedia";}}

		protected override void processMediaFile(FileInfo fi, IBizObj imgObj, string namePrefix)
		{
			base.processMediaFile(fi, imgObj, namePrefix);
			string url = string.Format("{0}{1}/{2}", PreviewBaseUrl, imgObj.get("location"), imgObj.get("name"));
			if (url.EndsWith(".image"))
				url = url.Substring(0, url.Length - "images".Length);
			imgObj.put("previewUrl", url);
		}
	}
}
